/*
 * Copyright 2025 LinQingYing. and contributors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * The use of this source code is governed by the Apache License 2.0,
 * which allows users to freely use, modify, and distribute the code,
 * provided they adhere to the terms of the license.
 *
 * The software is provided "as-is", and the authors are not responsible for
 * any damages or issues arising from its use.
 *
 */

package org.cangnova.cangjie.cjpm1.project.model.toml

import junit.framework.TestCase.assertEquals
import org.cangnova.cangjie.CangJieTestBase
import org.cangnova.cangjie.psi.CjPsiFactory
import org.junit.jupiter.api.assertThrows
import java.io.File

class CjpmTomlParserTest : CangJieTestBase() {

    private lateinit var factory: CjPsiFactory



    fun `test parse basic package config`() {
        val content = """
            [package]
            cjc-version = "0.55.3"
            compile-option = "-O2"
            description = "YAML解析工具"
            link-option = ""
            name = "yaml4cj"
            output-type = "dynamic"
            src-dir = "src"
            targetPlatform-dir = ""
            version = "0.0.1"
            package-configuration = {}
        """.trimIndent()

        val config = CjpmTomlParser.parse(content)

        assertNotNull(config.`package`)
        with(config.`package`) {
            assertEquals("0.55.3", this.cjcVersion)
            assertEquals("-O2", this?.compileOption)
            assertEquals("YAML解析工具", this?.description)
            assertEquals("", this?.linkOption)
            assertEquals("yaml4cj", name)
            assertEquals(OutputType.DYNAMIC, this?.outputType)
            assertEquals("src", this?.srcDir)
            assertEquals("", this?.targetDir)
            assertEquals("0.0.1", this?.version)
        }
    }


    fun `test parse dependencies`() {
        val content = """
          
            [package]
            name = "test"
            cjc-version = "0.55.3"
            version = "0.0.1"
            output-type = "dynamic"
            
            [dependencies]
            charset4cj = {branch = "v0.0.1.B002", git = "https://gitcode.com/Cangjie-TPC/charset4cj.git"}
            
        """.trimIndent()

        val config = CjpmTomlParser.parse(content)

        assertEquals(1, config.dependencies.size)
        with(config.dependencies["charset4cj"]!!) {
            assertEquals("v0.0.1.B002", branch)
            assertEquals("https://gitcode.com/Cangjie-TPC/charset4cj.git", git)
        }
    }


    fun `test parse target config`() {
        val content = """
            [targetPlatform.aarch64-linux-ohos]
            compile-option = "-B\"${"\$"}{DEVECO_CANGJIE_HOME}/compiler/third_party/llvm/bin\""
            
            [targetPlatform.aarch64-linux-ohos.bin-dependencies]
            path-option = ["${"\$"}{DEVECO_CANGJIE_HOME}/build/linux_ohos_aarch64_llvm/ohos"]
            package-option = {}
            
            [package]
            name = "test"
            cjc-version = "0.55.3"
            version = "0.0.1"
            output-type = "dynamic"
        """.trimIndent()

        val config = CjpmTomlParser.parse(content)

        val targetConfig = config.target["aarch64-linux-ohos"]
        assertNotNull(targetConfig)
        assertEquals("-B\"\${DEVECO_CANGJIE_HOME}/compiler/third_party/llvm/bin\"", targetConfig.compileOption)

        assertNotNull(targetConfig.binDependencies)
        assertEquals(1, targetConfig.binDependencies.pathOption?.size)
        assertEquals(
            "\${DEVECO_CANGJIE_HOME}/build/linux_ohos_aarch64_llvm/ohos",
            targetConfig.binDependencies.pathOption?.get(0)
        )
    }


    fun `test parse from file`() {
        val file = File(javaClass.getResource("/project_toml_files/14/cjpm.toml")!!.file)
        val config = CjpmTomlParser.parse(file)

        assertNotNull(config.`package`)
        assertEquals("yaml4cj", config.`package`.name)
    }


    fun `test write config to string`() {
        val config = CjpmTomlConfig(
            `package` = PackageConfig(
                cjcVersion = "0.55.3",
                name = "test",
                version = "0.0.1",
                outputType = OutputType.DYNAMIC
            )
        )

        val tomlString = CjpmTomlParser.writeToString(config)

        // Parse back to verify
        val parsedConfig = CjpmTomlParser.parse(tomlString)
        assertEquals(config.`package`?.name, parsedConfig.`package`?.name)
    }


    fun `test invalid TOML content`() {
        val invalidContent = """
            [package
            name = test
        """.trimIndent()

        assertThrows<Exception> {
            CjpmTomlParser.parse(invalidContent)
        }
    }


    fun `test parse profile config`() {
        val content = """
            [profile]
            build = { incremental = false, lto = "" }
            customized-option = { debug = "-g", release = "--fast-math -O2" }
            
            [profile.test]
            no-color = true
            timeout-each = "30s"
            random-seed = 12345
            bench = false
            report-path = "./test-report"
            report-format = "xml"
            verbose = true
            
            [profile.test.build]
            compile-option = "-O0"
            lto = "thin"
            mock = "mock-config"
            
            [profile.test.env]
            TEST_VAR = { value = "test_value", splice-type = "replace" }
            
            [profile.bench]
            no-color = false
            report-path = "./bench-report"
            baseline-path = "./baseline"
            report-format = "csv"
            
            [package]
            name = "test"
            cjc-version = "0.55.3"
            version = "0.0.1"
            output-type = "dynamic"
        """.trimIndent()

        val config = CjpmTomlParser.parse(content)

        assertNotNull(config.profile)
        with(config.profile) {
            // 验证 build 配置
            assertNotNull(this.build)
            assertEquals(false, build.incremental)
            assertEquals("", build.lto)

            // 验证自定义选项
            assertNotNull(customizedOption)
            assertEquals("-g", customizedOption["debug"])
            assertEquals("--fast-math -O2", customizedOption["release"])

            // 验证测试配置
            assertNotNull(test)
            with(test) {
                assertEquals(true, noColor)
                assertEquals("30s", timeoutEach)
                assertEquals(12345, randomSeed)
                assertEquals(false, bench)
                assertEquals("./test-report", reportPath)
                assertEquals("xml", reportFormat)
                assertEquals(true, verbose)

                // 验证测试构建配置
                assertNotNull(build)
                assertEquals("-O0", build.compileOption)
                assertEquals("thin", build.lto)
                assertEquals("mock-config", build.mock)

                // 验证环境变量配置
                assertNotNull(env)
                val testVar = env["TEST_VAR"]
                assertNotNull(testVar)
                assertEquals("test_value", testVar.value)
                assertEquals(SpliceType.REPLACE, testVar.spliceType)
            }

            // 验证性能测试配置
            assertNotNull(bench)
            with(bench) {
                assertEquals(false, noColor)
                assertEquals("./bench-report", reportPath)
                assertEquals("./baseline", baselinePath)
                assertEquals("csv", reportFormat)
            }
        }
    }


    fun `test parse ffi config`() {
        val content = """
            [ffi.c]
            latex = { path = "./libs/arm64-v8a/" }
            openssl = { path = "./libs/openssl/" }
            
            [package]
            name = "test"
            cjc-version = "0.55.3"
            version = "0.0.1"
            output-type = "dynamic"
        """.trimIndent()

        val config = CjpmTomlParser.parse(content)

        assertNotNull(config.ffi?.c)
        assertEquals(2, config.ffi.c.size)
        assertEquals("./libs/arm64-v8a/", config.ffi.c["latex"]?.path)
        assertEquals("./libs/openssl/", config.ffi.c["openssl"]?.path)
    }


    fun `test parse complex target config`() {
        val content = """
            [targetPlatform.x86_64-unknown-linux-gnu]
            compile-option = "-O2"
            override-compile-option = "--fast-math"
            link-option = "-static"
            
            [targetPlatform.x86_64-unknown-linux-gnu.dependencies]
            dep1 = { path = "./dep1" }
            dep2 = { git = "https://example.com/dep2.git", branch = "main" }
            
            [targetPlatform.x86_64-unknown-linux-gnu.test-dependencies]
            test-dep = { path = "./test-dep" }
            
            [targetPlatform.x86_64-unknown-linux-gnu.bin-dependencies]
            path-option = ["/usr/local/lib", "/opt/lib"]
            package-option = { "pkg1" = "/path/to/pkg1", "pkg2" = "/path/to/pkg2" }
            
            [targetPlatform.x86_64-unknown-linux-gnu.debug]
            compile-option = "-g"
            
            [targetPlatform.x86_64-unknown-linux-gnu.release]
            compile-option = "-O3"
            
            [package]
            name = "test"
            cjc-version = "0.55.3"
            version = "0.0.1"
            output-type = "dynamic"
        """.trimIndent()

        val config = CjpmTomlParser.parse(content)

        val targetConfig = config.target["x86_64-unknown-linux-gnu"]
        assertNotNull(targetConfig)

        with(targetConfig) {
            // 基本配置
            assertEquals("-O2", compileOption)
            assertEquals("--fast-math", overrideCompileOption)
            assertEquals("-static", linkOption)

            // 依赖配置
            assertNotNull(dependencies)
            assertEquals(2, dependencies.size)
            assertEquals("./dep1", dependencies["dep1"]?.path)
            assertEquals("https://example.com/dep2.git", dependencies["dep2"]?.git)
            assertEquals("main", dependencies["dep2"]?.branch)

            // 测试依赖配置
            assertNotNull(testDependencies)
            assertEquals(1, testDependencies.size)
            assertEquals("./test-dep", testDependencies["test-dep"]?.path)

            // 二进制依赖配置
            assertNotNull(binDependencies)
            assertEquals(2, binDependencies.pathOption?.size)
            assertEquals("/usr/local/lib", binDependencies.pathOption?.get(0))
            assertEquals("/opt/lib", binDependencies.pathOption?.get(1))
            assertEquals(2, binDependencies.packageOption?.size)
            assertEquals("/path/to/pkg1", binDependencies.packageOption?.get("pkg1"))
            assertEquals("/path/to/pkg2", binDependencies.packageOption?.get("pkg2"))

            // debug 配置
            assertNotNull(debug)
            assertEquals("-g", debug.compileOption)

            // release 配置
            assertNotNull(release)
            assertEquals("-O3", release.compileOption)
        }
    }


    fun `test parse workspace config`() {
        val content = """
            [workspace]
            members = [
                "packages/*",
                "tools/package1",
                "tools/package2"
            ]
            build-members = [
                "packages/core",
                "tools/package1"
            ]
            test-members = [
                "packages/core"
            ]
            compile-option = "-O2"
            override-compile-option = "--fast-math"
            link-option = "-static"
            targetPlatform-dir = "./targetPlatform"
            
            [package]
            name = "test"
            cjc-version = "0.55.3"
            version = "0.0.1"
            output-type = "dynamic"
        """.trimIndent()

        val config = CjpmTomlParser.parse(content)

        assertNotNull(config.workspace)
        with(config.workspace) {
            // 验证成员列表
            assertEquals(3, members.size)
            assertTrue(members.contains("packages/*"))
            assertTrue(members.contains("tools/package1"))
            assertTrue(members.contains("tools/package2"))

            // 验证构建成员列表
            assertNotNull(buildMembers)
            assertEquals(2, buildMembers.size)
            assertTrue(buildMembers.contains("packages/core"))
            assertTrue(buildMembers.contains("tools/package1"))

            // 验证测试成员列表
            assertNotNull(testMembers)
            assertEquals(1, testMembers.size)
            assertTrue(testMembers.contains("packages/core"))

            // 验证编译选项
            assertEquals("-O2", compileOption)
            assertEquals("--fast-math", overrideCompileOption)
            assertEquals("-static", linkOption)
            assertEquals("./targetPlatform", targetDir)
        }
    }
} 